package com.koron.standard.patrolLine.excel;

import cn.hutool.core.map.BiMap;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.koron.common.core.business.common.entity.TOrderNoMax;
import com.koron.common.core.business.common.service.TOrderNoMaxService;
import com.koron.common.core.business.datadict.utils.DataDictTool;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.standard.patrolLine.bean.excel.LinePatrolExcel;
import com.koron.standard.patrolLine.bean.po.LinePatrol;
import com.koron.standard.patrolLine.bean.po.LinePatrolCheck;
import com.koron.standard.patrolLine.bean.po.LinePatrolRecord;
import com.koron.standard.patrolLine.service.LinePatrolCheckService;
import com.koron.standard.patrolLine.service.LinePatrolRecordService;
import com.koron.standard.patrolLine.service.LinePatrolService;
import com.koron.standard.utils.StandardCodeTools;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author jzp
 * @since 2022/5/16
 */
@Slf4j
public class LinePatrolExcelListener extends AnalysisEventListener<LinePatrolExcel> {
    private static final int BATCH_COUNT = 100;

    private String prePatrolId;
    private Integer preRowIndex;
    private Integer checkStatus;
    private Integer recordStatus;

    /**
     * 缓存的数据
     */
    private final List<LinePatrol> linePatrolList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<LinePatrolCheck> linePatrolCheckList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<LinePatrolRecord> linePatrolRecordList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    private final LinePatrolService linePatrolService;
    private final LinePatrolCheckService linePatrolCheckService;
    private final LinePatrolRecordService linePatrolRecordService;
    private final TOrderNoMaxService tOrderNoMaxService;

    public LinePatrolExcelListener(LinePatrolService linePatrolService, LinePatrolCheckService linePatrolCheckService, LinePatrolRecordService linePatrolRecordService, TOrderNoMaxService tOrderNoMaxService){
        this.linePatrolService = linePatrolService;
        this.linePatrolCheckService = linePatrolCheckService;
        this.linePatrolRecordService = linePatrolRecordService;
        this.tOrderNoMaxService = tOrderNoMaxService;
    }

    @Override
    public void invoke(LinePatrolExcel data, AnalysisContext context) {
        Integer rowIndex = context.readRowHolder().getRowIndex();
        // 如果分类编码和名称不为空，则创建一条设备分类数据
        if (StrUtil.isNotEmpty(data.getTypeId()) && StrUtil.isNotEmpty(data.getName())) {
            LinePatrol linePatrol = data.buildPatrol();
            linePatrolList.add(linePatrol);
            prePatrolId = linePatrol.getId();
            preRowIndex = rowIndex;
        }

        // 如果检查项名称不为空。则创建检查项
        if (StrUtil.isNotEmpty(data.getCheckName())) {
            LinePatrolCheck check = data.buildPatrolCheck(prePatrolId, rowIndex - preRowIndex, checkStatus);
            checkStatus = check.getStatus();
            linePatrolCheckList.add(check);
            // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
            if (linePatrolCheckList.size() >= BATCH_COUNT) {
                savePatrolCheck();
                // 存储完成清理 list
                linePatrolCheckList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }

        // 如果记录项名称不为空。则创建数据记录项
        if (StrUtil.isNotEmpty(data.getRecordName())) {
            LinePatrolRecord record = data.buildPatrolRecord(prePatrolId, rowIndex - preRowIndex, recordStatus);
            recordStatus = record.getStatus();
            linePatrolRecordList.add(record);
            // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
            if (linePatrolRecordList.size() >= BATCH_COUNT) {
                savePatrolRecord();
                // 存储完成清理 list
                linePatrolRecordList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        savePatrol();
        savePatrolCheck();
        savePatrolRecord();
        log.info("所有数据解析完成！");
    }

    private void savePatrol() {
        if (linePatrolList.size() == 0) {
            return;
        }
        // 设置code, appid, sort
        // 1.1 获取当天最大编码
        TOrderNoMax maxNo = tOrderNoMaxService.peekNoMax(StandardCodeTools.patrolPrefix, null, linePatrolList.size());
        String prifix = StandardCodeTools.patrolPrefix + maxNo.getDate();
        AtomicInteger atomicInteger = new AtomicInteger(maxNo.getMaxValue()- linePatrolList.size());
        // 1.2 获取水司id
        String appId = ThreadLocalContext.get().getAppId();

        // 转化字典
        BiMap<String, String> standardTypeDict = new BiMap<>(DataDictTool.getDataDictByCode("standardManagement", "standard_patrol_type"));
        for (LinePatrol linePatrol : linePatrolList) {
            linePatrol.setCode(prifix + String.format("%0" + 4 + "d", atomicInteger.getAndIncrement()));
            linePatrol.setAppid(appId);
            linePatrol.setStandardType(standardTypeDict.getKey(linePatrol.getStandardType()));
        }
        log.info("{}条巡视数据，开始存储数据库！", linePatrolList.size());
        linePatrolService.saveBatch(linePatrolList);
        log.info("存储数据库成功！");
    }

    private void savePatrolCheck() {
        log.info("{}条检查项数据，开始存储数据库！", linePatrolCheckList.size());
        linePatrolCheckService.saveBatch(linePatrolCheckList);
        log.info("存储数据库成功！");
    }

    private void savePatrolRecord() {
        log.info("{}条记录项数据，开始存储数据库！", linePatrolRecordList.size());
        linePatrolRecordService.saveBatch(linePatrolRecordList);
        log.info("存储数据库成功！");
    }

}
